# coding:utf8

from appserver import db_store
from sqlalchemy.orm import relationship, backref
import traceback
import hashlib
from models.entity.organization import Organization
from models.entity.department import Department
from models.entity.role_with_user import RoleWithUser
from sqlalchemy import or_


class User(db_store.Model):
    __tablename__ = "users"
    __bind_key__ = "main"

    id = db_store.Column(db_store.Integer, primary_key=True, comment=u"用户编号")
    username = db_store.Column(db_store.String(80), unique=True, nullable=False, comment=u"用户名")
    email = db_store.Column(db_store.String(120), unique=True, comment=u"邮箱")
    phone_number = db_store.Column(db_store.String(11), unique=True, comment=u"手机")
    password = db_store.Column(db_store.String(32), comment=u"密码")
    safe_code = db_store.Column(db_store.String(64), unique=True, comment=u"安全码")
    job_number = db_store.Column(db_store.String(64), unique=True, comment=u"工号")
    sex = db_store.Column(db_store.Integer, comment="性别")  # 1-男性 0-女性
    department_id = db_store.Column(db_store.Integer, db_store.ForeignKey("departments.id"))
    organization_id = db_store.Column(db_store.Integer, db_store.ForeignKey('organizations.id'),
                                      comment=u"组织机构ID")
    description = db_store.Column(db_store.String(128), comment="备注")
    status = db_store.Column(db_store.Integer, default=0, comment=u"状态")  # 0-正常 1-禁用

    def __repr__(self):
        return '<User %r>' % self.username

    def save(self):
        if self.username is None:
            print("user save error: username cannot be empty")
            return -2
        if self.password is None:
            print("user save error: password cannot be empty")
            return -3
        try:
            db_store.session.add(self)
            db_store.session.commit()
            return 0
        except:
            print(
                "----------------------------------table users write error:\n----------------------------------\n%s\n----------------------------------" % (
                    traceback.format_exc()))
            return -1

    def delete(self):
        try:
            db_store.session.delete(self)
            db_store.session.commit()
            return 0
        except:
            print(
                "----------------------------------table users write error:\n----------------------------------\n%s\n----------------------------------" % (
                    traceback.format_exc()))
            return -1

    @staticmethod
    def get_user_all():
        # 以python列表形式返回所有用户
        return User.query.all()

    @staticmethod
    def get_user_by_id(id_num):
        # 通过指定id返回特定用户实例,若用户不存在则返回None
        return User.query.filter_by(id=id_num).first()

    @staticmethod
    def get_user_by_username(username):
        # 通过指定username获取用户实例
        return User.query.filter_by(username=username).first()

    @staticmethod
    def get_user_by_email(email):
        # 通过指定email获取用户实例
        return User.query.filter_by(email=email).first()

    @staticmethod
    def get_user_by_phone_number(phone_number):
        # 通过指定phone_number获取用户实例
        return User.query.filter_by(phone_number=phone_number).first()

    @staticmethod
    def get_user_by_safe_code(safe_code):
        # 通过指定safe_code获取用户实例
        return User.query.filter_by(safe_code=safe_code).first()

    @staticmethod
    def get_users_by_organization_id(organization_id):
        # 通过机构id获取用户列表
        return User.query.filter_by(organization_id=organization_id).all()

    @staticmethod
    def get_users_by_department_id(department_id):
        # 通过部门id获取用户列表
        return User.query.filter_by(department_id=department_id).all()

    @staticmethod
    def get_users_by_role_id(role_id):
        # 通过角色id获取用户列表
        return [ User.query.filter_by(id=connector.user_id).first() for connector in RoleWithUser.query.filter_by(role_id=role_id).all() ]

    @staticmethod
    def verify_user(username, password):
        # 核实用户
        # 返回值:
        # -1: 用户不存在
        # -2: 密码不正确
        #  0: 用户名密码正确
        the_user = User.get_user_by_username(username)
        if the_user == None:
            # 用户不存在
            return -1
        # print("user_password: %s" % the_user.password)
        # print("input_password: %s" % hashlib.md5(password.encode("utf-8")).hexdigest())

        if (hashlib.md5(password.encode("utf-8")).hexdigest()) != the_user.password:
            print("user_password: %s" % the_user.password)
            print("input_password: %s" % hashlib.md5(password.encode("utf-8")).hexdigest())
            # 密码不正确
            return -2
        return 0

    @staticmethod
    def check_user_email(email):
        # 检查该邮箱是否为被注册,是则返回True,否则返回False
        if User.query.filter_by(email=email).first() is None:
            return False
        else:
            return True

    @staticmethod
    def check_user_phone_number(phone_number):
        # 检查该手机号是否为被注册,是则返回True,否则返回False
        if User.query.filter_by(phone_number=phone_number).first() is None:
            return False
        else:
            return True

    @staticmethod
    def get_user_dic(the_user):
        # 以python字典的形式返回某个用户的所有信息
        the_department = Department().get_entity_by_id(the_user.department_id)
        if the_department is None:
            department_name = None
        else:
            department_name = the_department.name
        rdic = {}
        rdic["id"] = the_user.id
        rdic["username"] = the_user.username
        rdic["email"] = the_user.email
        rdic["phone_number"] = the_user.phone_number
        rdic["password"] = the_user.password
        rdic["safe_code"] = the_user.safe_code  # 账户
        rdic["job_number"] = the_user.job_number  # 工号
        rdic["department_id"] = the_user.department_id
        rdic["department_name"] = department_name
        rdic["organization_id"] = the_user.organization_id
        rdic["sex"] = the_user.sex
        rdic["description"] = the_user.description
        return rdic

    @staticmethod
    def add_roles_to_user(the_user, roles):
        # 为指定用户添加指定角色
        for role in roles:
            role_connector = RoleWithUser()
            role_connector.user_id = the_user.id
            role_connector.role_id = role.id
            if role_connector.save() != 0:
                print("add_roles_to_user error: RoleWithUser save error")
                return -1
        return 0

    @staticmethod
    def add_user(user_dic):
        new_user = User()
        if not "username" in user_dic:
            print("add_user error: username cannot be empty")
            return -1
        if not "password" in user_dic:
            print("add_user error: password cannot be empty")
            return -2
        new_user.username = user_dic["username"]
        new_user.password = hashlib.md5(user_dic["password"].encode("utf-8")).hexdigest()
        if "email" in user_dic:
            new_user.email = user_dic["email"]
        if "phone_number" in user_dic:
            new_user.phone_number = user_dic["phone_number"]
        if "safe_code" in user_dic:
            new_user.safe_code = user_dic["safe_code"]
        if "job_number" in user_dic:
            new_user.job_number = user_dic["job_number"]
        if "sex" in user_dic:
            new_user.sex = user_dic["sex"]
        if "status" in user_dic:
            new_user.status = user_dic["status"]
        if User.query.filter_by(username=user_dic["username"]).first():
            raise RuntimeError("用户名已存在")
        if User.query.filter_by(email=user_dic["email"]).first():
            raise RuntimeError("邮箱已存在")
        if User.query.filter_by(phone_number=user_dic["phone_number"]).first():
            raise RuntimeError("手机号已存在")
        if User.query.filter_by(safe_code=user_dic["safe_code"]).first():
            raise RuntimeError("安全码已存在")
        if User.query.filter_by(job_number=user_dic["job_number"]).first():
            raise RuntimeError("工号已存在")
        if_department = False
        if "department_id" in user_dic:
            the_department = Department().get_entity_by_id(user_dic["department_id"])
            if not the_department:
                print("add_user error: department(id=%d) is not exist" % user_dic["department_id"])
                return -6
            new_user.department_id = user_dic["department_id"]
            new_user.organization_id = the_department.org_id
            if_department = True
        if "organization_id" in user_dic and if_department == False:
            if not Organization.get_organization_by_id(user_dic["organization_id"]):
                print("add_user error: organization(id=%d) is not exist" % user_dic["organization_id"])
                return -5
            new_user.organization_id = user_dic["organization_id"]
        if "description" in user_dic:
            new_user.description = user_dic["description"]
        ret = new_user.save()
        if ret != 0:
            print("add_user error: user save error")
            return -7
        save_list = []
        for item in user_dic["roles"]:
            role_connector = RoleWithUser()
            role_connector.role_id = item.id
            role_connector.user_id = new_user.id
            ret = role_connector.save()
            if ret != 0:
                print("add_user error: roles_with_users save error")
                for t_item in save_list:
                    if t_item.delete() != 0:
                        print("add_user error: delete error")
                        return -4
                return -3
            save_list.append(role_connector)
        return new_user

    @staticmethod
    def search(query_word):
        search_list = User.query.filter(
            or_(User.username.like("%" + query_word + "%"), User.email.like("%" + query_word + "%"),
                User.email.like("%" + query_word + "%"), User.phone_number.like("%" + query_word + "%"),
                User.safe_code.like("%" + query_word + "%"), User.job_number.like("%" + query_word + "%"),
                User.description.like("%" + query_word + "%"))).all()
        tlist = []
        for item in search_list:
            tlist.append(User.get_user_dic(item))
        rdic = {
            "success": 1,
            "error_code": None,
            "error_msg": None,
            "data": tlist
        }
        return rdic
